1   /*
2    * Copyright (C) 2007 The Guava Authors
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    * http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  package com.google.common.collect;
18  
19  import static com.google.common.collect.Multisets.setCountImpl;
20  
21  import com.google.common.annotations.GwtCompatible;
22  import com.google.common.base.Objects;
23  
24  import java.util.AbstractCollection;
25  import java.util.Collection;
26  import java.util.Iterator;
27  import java.util.Set;
28  
29  import javax.annotation.Nullable;
30  
31  /**
32   * This class provides a skeletal implementation of the {@link Multiset}
33   * interface. A new multiset implementation can be created easily by extending
34   * this class and implementing the {@link Multiset#entrySet()} method, plus
35   * optionally overriding {@link #add(Object, int)} and
36   * {@link #remove(Object, int)} to enable modifications to the multiset.
37   *
38   * <p>The {@link #count} and {@link #size} implementations all iterate across
39   * the set returned by {@link Multiset#entrySet()}, as do many methods acting on
40   * the set returned by {@link #elementSet()}. Override those methods for better
41   * performance.
42   *
43   * @author Kevin Bourrillion
44   * @author Louis Wasserman
45   */
46  @GwtCompatible
47  abstract class AbstractMultiset<E> extends AbstractCollection<E>
48      implements Multiset<E> {
49    // Query Operations
50  
51    @Override public int size() {
52      return Multisets.sizeImpl(this);
53    }
54  
55    @Override public boolean isEmpty() {
56      return entrySet().isEmpty();
57    }
58  
59    @Override public boolean contains(@Nullable Object element) {
60      return count(element) > 0;
61    }
62  
63    @Override public Iterator<E> iterator() {
64      return Multisets.iteratorImpl(this);
65    }
66  
67    @Override
68    public int count(@Nullable Object element) {
69      for (Entry<E> entry : entrySet()) {
70        if (Objects.equal(entry.getElement(), element)) {
71          return entry.getCount();
72        }
73      }
74      return 0;
75    }
76  
77    // Modification Operations
78  
79    @Override public boolean add(@Nullable E element) {
80      add(element, 1);
81      return true;
82    }
83  
84    @Override
85    public int add(@Nullable E element, int occurrences) {
86      throw new UnsupportedOperationException();
87    }
88  
89    @Override public boolean remove(@Nullable Object element) {
90      return remove(element, 1) > 0;
91    }
92  
93    @Override
94    public int remove(@Nullable Object element, int occurrences) {
95      throw new UnsupportedOperationException();
96    }
97  
98    @Override
99    public int setCount(@Nullable E element, int count) {
100     return setCountImpl(this, element, count);
101   }
102 
103   @Override
104   public boolean setCount(@Nullable E element, int oldCount, int newCount) {
105     return setCountImpl(this, element, oldCount, newCount);
106   }
107 
108   // Bulk Operations
109 
110   /**
111    * {@inheritDoc}
112    *
113    * <p>This implementation is highly efficient when {@code elementsToAdd}
114    * is itself a {@link Multiset}.
115    */
116   @Override public boolean addAll(Collection<? extends E> elementsToAdd) {
117     return Multisets.addAllImpl(this, elementsToAdd);
118   }
119 
120   @Override public boolean removeAll(Collection<?> elementsToRemove) {
121     return Multisets.removeAllImpl(this, elementsToRemove);
122   }
123 
124   @Override public boolean retainAll(Collection<?> elementsToRetain) {
125     return Multisets.retainAllImpl(this, elementsToRetain);
126   }
127 
128   @Override public void clear() {
129     Iterators.clear(entryIterator());
130   }
131 
132   // Views
133 
134   private transient Set<E> elementSet;
135 
136   @Override
137   public Set<E> elementSet() {
138     Set<E> result = elementSet;
139     if (result == null) {
140       elementSet = result = createElementSet();
141     }
142     return result;
143   }
144 
145   /**
146    * Creates a new instance of this multiset's element set, which will be
147    * returned by {@link #elementSet()}.
148    */
149   Set<E> createElementSet() {
150     return new ElementSet();
151   }
152 
153   class ElementSet extends Multisets.ElementSet<E> {
154     @Override
155     Multiset<E> multiset() {
156       return AbstractMultiset.this;
157     }
158   }
159 
160   abstract Iterator<Entry<E>> entryIterator();
161 
162   abstract int distinctElements();
163 
164   private transient Set<Entry<E>> entrySet;
165 
166   @Override public Set<Entry<E>> entrySet() {
167     Set<Entry<E>> result = entrySet;
168     if (result == null) {
169       entrySet = result = createEntrySet();
170     }
171     return result;
172   }
173 
174   class EntrySet extends Multisets.EntrySet<E> {
175     @Override Multiset<E> multiset() {
176       return AbstractMultiset.this;
177     }
178 
179     @Override public Iterator<Entry<E>> iterator() {
180       return entryIterator();
181     }
182 
183     @Override public int size() {
184       return distinctElements();
185     }
186   }
187 
188   Set<Entry<E>> createEntrySet() {
189     return new EntrySet();
190   }
191 
192   // Object methods
193 
194   /**
195    * {@inheritDoc}
196    *
197    * <p>This implementation returns {@code true} if {@code object} is a multiset
198    * of the same size and if, for each element, the two multisets have the same
199    * count.
200    */
201   @Override public boolean equals(@Nullable Object object) {
202     return Multisets.equalsImpl(this, object);
203   }
204 
205   /**
206    * {@inheritDoc}
207    *
208    * <p>This implementation returns the hash code of {@link
209    * Multiset#entrySet()}.
210    */
211   @Override public int hashCode() {
212     return entrySet().hashCode();
213   }
214 
215   /**
216    * {@inheritDoc}
217    *
218    * <p>This implementation returns the result of invoking {@code toString} on
219    * {@link Multiset#entrySet()}.
220    */
221   @Override public String toString() {
222     return entrySet().toString();
223   }
224 }